package my.springboot.service.impl;

import my.springboot.service.GlobalLockService;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @author fengbo
 */
@Service
public class GlobalLockServiceImpl implements GlobalLockService {

    /** 分布式锁的Redis关键字 */
    private final static String LOCK_KEY_VALUE = "GLOBAL_LOCK:KEY:%s";
    /** 单个业务持有锁的默认时间30s，防止死锁 */
    private final static long LOCK_EXPIRE = 30 * 1000L;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean lock(String key, String value) {
        return lock(key, value, LOCK_EXPIRE, TimeUnit.MILLISECONDS);
    }

    @Override
    public boolean lock(String key, String value, long expire, TimeUnit expireUnit) {
        key = String.format(LOCK_KEY_VALUE, key);
        Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, value, expire, expireUnit);
        return Boolean.TRUE.equals(ret);
    }

    @Override
    public boolean unlock(String key, String value) {
        key = String.format(LOCK_KEY_VALUE, key);
        DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setResultType(Long.class);
        defaultRedisScript.setScriptText("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end ");
        Long ret = redisTemplate.execute(defaultRedisScript, Collections.singletonList(key), value);
        return NumberUtils.LONG_ONE.equals(ret);
    }

}
